
(* TODO *)
let shutdownConnection channel = ()

(* create server *)
let serverRun port handler = 
    (* create address "ANY" *)
    let addr = Unix.ADDR_INET (Unix.inet_addr_any, port) in
    (* create socket *)
    let socket = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
    let () = 
        try
            (* bind the socket to the addres *)
            let () = Unix.bind socket addr in
            (* listen on it -- create a server *)
            let () = Unix.listen socket 10 in
            ()
        with excptn -> 
            (* close the socket first *)
            let () = Unix.close socket in 
            (* reraise *)
            raise excptn
    in
    (* main server loop *)
    let rec serverLoop () = 
		let (client, addr) = Unix.accept socket in
		let in_channel = Unix.in_channel_of_descr client in
        let out_channel = Unix.out_channel_of_descr client in
		(* TODO save children somewhere *)
        let _ = Thread.create handler (in_channel, out_channel) in
        serverLoop ()
    in try serverLoop ()
    with excptn -> 
        (* close the server socket if something goes wrong *)
        let () = Unix.close socket in 
        raise excptn



(* ge is game engine state *)
let stdinHandler ge (in_channel, out_channel) = 
	let () = Printf.fprintf out_channel "> " in
	let () = flush out_channel in
	let rec loop () = 
		let line = input_line in_channel in
		let () = 
			try
				let command = Types.Data.read line in
				(* TODO handle quit command *)
				let result = GameEngine.adminCommand ge command in
				let () = Printf.fprintf out_channel 
					"%s\n> " (Types.Data.show result)  in
				let () = flush out_channel in
				()
			with Types.Data.BadParse s ->
				let () = Printf.fprintf out_channel "Bad parse: %s\n> " s in
				let () = flush out_channel in
				()
		in loop ()
	in loop ()

let socketHandler ge (in_channel, out_channel) = 
	let player = GameEngine.newPlayer ge in
	try
		let rec loop () = 
			let line = input_line in_channel in
			let () = try
					let command = Types.Data.read line in
					let result = GameEngine.playerCommand ge player command in
					let () = Printf.fprintf out_channel "%s\n" (Types.Data.show result) in
					let () = flush out_channel in
					()
				with Types.Data.BadParse s -> ()
			in loop ()
		in loop ()
	with End_of_file ->
			let () = GameEngine.unregisterPlayer ge player in
			let () = shutdownConnection in_channel in
			()
		| exn ->
			let () = GameEngine.unregisterPlayer ge player in
			let () = shutdownConnection in_channel in
			raise exn

let server ge = 
	serverRun Config.portNumber (socketHandler ge)

let engine ge = 
	let rec loop () = 
		let () = GameEngine.step ge in
		let () = Thread.delay Config.dt in
		loop ()
	in loop ()

let main () = 
	let mapFilename = Sys.argv.(1) in
	let ge = GameEngine.init mapFilename in
	let serverThread = Thread.create server ge in
	let engineThread = Thread.create engine ge in
	let () = stdinHandler ge (stdin, stdout) in
	let () = Thread.kill serverThread in
	let () = Thread.kill engineThread in
	()

let () = main ()

